#include <graphics.h>
#include <conio.h>
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <sstream>

#define ATLEFT 250
#define ATRIGHT 550
#define BTLEFT 750
#define BTRIGHT 950
#define CTLEFT 1050
#define CTRIGHT 1350
#define TOP 795
#define BOTTOM 770
#define TO_STRING(num)     ( ((ostringstream&)(ostringstream()<<num)).str() )
using namespace std;

int step = 0;
int n = 0;
struct rec;

struct T {
    T(char name, int n) {
        this->name = name;
        num = n;
    }
    char name;
    int num;
    rec *rect;
};

T A('A', 0);
T B('B', 0);
T C('C', 0);
void move(T &from, T &to);
int get_nums(vector<rec> r);
void show(T from, T to);
struct rec {
    rec(T t) : recs(7)
    {
        switch (t.name)
        {
            case 'A' : left = ATLEFT; right = ATRIGHT; break;
            case 'B' : left = BTLEFT; right = BTRIGHT; break;
            case 'C' : left = CTLEFT; right = CTRIGHT; break;
        };
        int height = t.num;
        recs.erase(recs.begin() + height, recs.end());
        top = TOP, bottom = BOTTOM;
        for (int i = height - 1; i >= 0 ; i--) {
            recs[i] = rec(left, right, top, bottom);
            left += 20;
            right -= 20;
            top -= 30;
            bottom -= 30;
        }
    }
    rec(int l, int r, int t, int b) : left(l), right(r), top(t), bottom(b) {}
    rec& operator= (rec r) {
        if (this != &r)
        {
            this->left = r.left;
            this->right = r.right;
            this->top = r.top;
            this->bottom = r.bottom;
            this->recs = r.recs;
        }
        return *this;
    }
    rec() : left(0), right(0), top(0), bottom(0) {}
    int left;
    int right;
    int top;
    int bottom;
    vector<rec> recs;
};

void hani_init(rec arec) {
    initgraph(1500, 800);
    settextstyle(30, 0, _T("Consolas"));
    outtextxy(400, 100, _T("A"));
	rectangle(400, 180, 410, 800);          //生成A柱子(左，高，右，底)
//	A.num = n;
//	static rec arec(A);
//	A.rect = &arec;
	for (int i = 0; i < n; i++)
	{
	    rectangle(arec.recs[i].left, arec.recs[i].top, arec.recs[i].right, arec.recs[i].bottom);
	}
	outtextxy(800, 100, _T("B"));
	rectangle(800, 180, 810, 800);          //生成B柱子
	outtextxy(1200, 100, _T("C"));
	rectangle(1200, 180, 1210, 800);        //生成C柱子
}

void hanoi(int n,T A,T B,T C)
{
    if(n == 1)
    {
        step++;
//        cout<<"["<<step<<"]move 1# from "<<A.name<<" to "<<C.name<<endl;
//        cout << "移动前" << endl;
//        cout << A.name << get_nums(A.rect->recs) << endl;
//        cout << C.name << get_nums(C.rect->recs) << endl;
        move(A, C);
        show(A, C);
        getch();
//        cout << "移动后" << endl;
//        cout << A.name << get_nums(A.rect->recs) << endl;
//        cout << C.name << get_nums(C.rect->recs) << endl;
    }
    else
    {
        hanoi(n-1,A,C,B);
        step++;
//        cout<<"["<<step<<"]move "<<n<<"# from "<<A.name<<" to "<<C.name<<endl;
//        cout << "移动前" << endl;
//        cout << A.name << get_nums(A.rect->recs) << endl;
//        cout << C.name << get_nums(C.rect->recs) << endl;
        move(A, C);
        show(A, C);
        getch();
//        cout << "移动后" << endl;
//        cout << A.name << get_nums(A.rect->recs) << endl;
//        cout << C.name << get_nums(C.rect->recs) << endl;
        hanoi(n-1,B,A,C);
    }

}

int get_nums(vector<rec> r) {
    int res = 0;
    for (auto &a : r){
        if (a.bottom != 0)
        {
//            cout << res+1 << endl;
//            cout << a.top << endl;
//            cout << a.bottom << endl;
//            cout << a.left << endl;
//            cout << a.right << endl;
            res++;
        }
    }
    return res;
}

int get_times(T from, T to) {
    if (from.name == 'A')
    {
        if (to.name == 'B')
            return 1;
        else if (to.name == 'C')
            return 2;
    }
    else if (from.name == 'B')
    {
        if (to.name == 'A')
            return -1;
        else if (to.name == 'C')
            return 1;
    }
    else if (from.name == 'C')
    {
        if (to.name == 'A')
            return -2;
        else if (to.name == 'B')
            return -1;
    }
    return 0;
}

//vector<rec>::iterator find_first(vector<rec> recs){
//    for (auto i = recs.begin(); i != recs.end(); i++)
//            if (i->bottom != 0)
//            {
//                return i;
//            }
//    return recs.end();
//}

void move(T &from, T &to) {
//    int nums = get_nums(to.rect->recs);
//    cout << nums << endl;
    int to_nums = get_nums(to.rect->recs);
    int times = get_times(from, to);
//    auto p = find_first(from.rect->recs);
//    p->left += times * 400;
//    p->right += times * 400;
    (from.rect->recs.begin())->left += times * 400;
    (from.rect->recs.begin())->right += times * 400;
//    p->top = TOP - to_nums*30;
//    p->bottom = BOTTOM - to_nums*30;
//    to.rect->recs.emplace_back(*p);
//    from.rect->recs.erase(p);
    (from.rect->recs.begin())->top = TOP - to_nums*30;
    (from.rect->recs.begin())->bottom = BOTTOM - to_nums*30;
    to.rect->recs.insert(to.rect->recs.begin(), *from.rect->recs.begin());
    get_nums(from.rect->recs);
    from.rect->recs.erase(from.rect->recs.begin());
}

void show(T from, T to) {
    cleardevice();
    string alert;
    char sfrom = from.name;
    char tfrom = to.name;
    alert = "[" + TO_STRING(step) + "]" + "move from" + "   " + sfrom + "   " +  "to" + "   " + tfrom;
    char aler[50] = {"按任意键继续"};
    char buf[50];
    strcpy(buf, alert.c_str());
    outtextxy(550, 20, _T(buf));
    outtextxy(650, 50, _T(aler));
    outtextxy(400, 100, _T("A"));
	rectangle(400, 180, 410, 800);          //生成A柱子(左，高，右，底)
	int anums = get_nums(A.rect->recs);
	for (int i = 0; i < anums; i++)
	{
	    rectangle(A.rect->recs[i].left, A.rect->recs[i].top, A.rect->recs[i].right, A.rect->recs[i].bottom);
	}
	outtextxy(800, 100, _T("B"));
	rectangle(800, 180, 810, 800);          //生成B柱子
	int bnums = get_nums(B.rect->recs);
	for (int i = 0; i < bnums; i++)
	{
	    rectangle(B.rect->recs[i].left, B.rect->recs[i].top, B.rect->recs[i].right, B.rect->recs[i].bottom);
	}
	outtextxy(1200, 100, _T("C"));
	rectangle(1200, 180, 1210, 800);        //生成C柱子
	int cnums = get_nums(C.rect->recs);
    for (int i = 0; i < cnums; i++)
	{
	    rectangle(C.rect->recs[i].left, C.rect->recs[i].top, C.rect->recs[i].right, C.rect->recs[i].bottom);
	}
}

int main()
{
    cout << "请输入圆盘个数(小于七个)" << endl;
    cin >> n;
    if (n > 7)
        return 0;
    A.num = n;
    rec arec(A);
    rec brec(B);
    rec crec(C);
	A.rect = &arec;
	B.rect = &brec;
	C.rect = &crec;
	B.rect->recs = vector<rec>(0);
	C.rect->recs = vector<rec>(0);
    hani_init(arec);
    getch();
    hanoi(n, A, B, C);
//    hani_init(arec);
	closegraph();
	getch();
	return 0;
}

